///
///Author: lizhi
///Description: 文件上传器
///Date: 2024-07-22 19:19:42
///LastEditTime: 2024-07-22 19:19:42
///
import 'dart:async';
import 'dart:core';

import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:flutter/foundation.dart';
import 'package:uuid/uuid.dart';

import 'api_request.dart';

enum FileUploaderStatus { prepare, uploading, success, failed, canceled }

class FileUploaderTask {
  String taskId;
  FileUploaderStatus status;
  String localPath;
  List<int>? fileBytes;
  String? name;
  String? key;

  /// 已经拼接好的url  host+key    host由接口[apiImageToken]返回
  String? imageUrl;
  int size;

  ///进度值 0 - 100
  int progress;
  String? errMessage;
  CancelToken? _cancelToken;
  List<String> uploadRecords = [];

  MultipartFile get multipartFile {
    if (fileBytes != null) {
      return MultipartFile.fromBytes(fileBytes!, filename: name);
    } else {
      return MultipartFile.fromFileSync(localPath, filename: name);
    }
  }

  ///上传状态改变回调  上传进度，每800毫秒更新，参数>=0 <=100
  void Function(FileUploaderTask)? _onUploadChanged;

  FileUploaderTask(this.taskId, this.localPath,
      {this.status = FileUploaderStatus.prepare,
      this.name,
      this.key,
      this.fileBytes,
      this.size = 0,
      this.progress = 0}) {
    _cancelToken = CancelToken();
  }
}

class FileUploader {
  static const apiImageToken = "/api/image";
  static const apiQiniuUpload = "http://upload.qiniu.com";

  List<FileUploaderTask> _taskQueue = [];
  List<FileUploaderTask> _finishedTasks = [];
  bool _isRunning = false;

  ///构造七牛上传服务
  late Dio _dio;

  FileUploader() {
    var options = BaseOptions(
        connectTimeout: const Duration(milliseconds: 8000),
        receiveTimeout: const Duration(milliseconds: 10000));
    _dio = Dio(options);
    _dio.interceptors
        .add(LogInterceptor(requestBody: true, responseBody: true));
    if (!kIsWeb) {
      if (Api.shareInstance().proxy?.isNotEmpty == true) {
        (_dio.httpClientAdapter as DefaultHttpClientAdapter)
            .onHttpClientCreate = (client) {
          client.findProxy = (uri) {
            return "PROXY ${Api.shareInstance().proxy}";
          };
          client.badCertificateCallback = (cert, host, port) => true;
        };
      } else {
        (_dio.httpClientAdapter as DefaultHttpClientAdapter)
            .onHttpClientCreate = (client) {
          client.badCertificateCallback = (cert, host, port) => true;
        };
      }
    }
  }

  ///新增上传, 返回上传校验是否成功
  FileUploaderTask? startUpload(
    String localPath,
    String name,
    int size, {
    void Function(FileUploaderTask)? onUploadChanged,
    List<int>? fileBytes,
  }) {
    if (localPath.isNotEmpty == true || fileBytes?.isNotEmpty == true) {
      var task = FileUploaderTask(Uuid().v4(), localPath,
          name: name, size: size, fileBytes: fileBytes);
      task._onUploadChanged = onUploadChanged;
      _addTask(task);
      return task;
    } else {
      return null;
    }
  }

  ///取消上传任务
  void cancelTask(FileUploaderTask task) {
    task.status = FileUploaderStatus.canceled;
    task._cancelToken!.cancel();
    _taskQueue.remove(task);
  }

  ///取消所有任务
  void cancelAll() {
    _taskQueue.forEach((t) {
      t.status = FileUploaderStatus.canceled;
      t._cancelToken!.cancel();
    });
    _taskQueue.clear();
    _isRunning = false;
  }

  ///取消所有任务，并清空已上传成功的任务
  void clear() {
    cancelAll();
    _finishedTasks.clear();
  }

  ///添加上传任务
  void _addTask(FileUploaderTask task) {
    _taskQueue.add(task);
    if (!_isRunning) {
      _executeTask();
    }
  }

  ///执行上传
  Future _executeTask() async {
    while (_taskQueue.isNotEmpty) {
      _isRunning = true;

      var task = _taskQueue.removeAt(0);
      print('Upload task: ${task.name}');
      task.status = FileUploaderStatus.uploading;
      task.uploadRecords.clear();
      task.uploadRecords.add('开始调接口/api/image 获取上传信息');
      var result = await Api.shareInstance()
          .get(apiImageToken, cancelToken: task._cancelToken);
      task.uploadRecords.add(
          '接口/api/image返回结果：code:${result.code}  message:${result.message}  data:${result.data}');

      if (result.code == 200) {
        var refreshTime = DateTime.now();
        task.key = result.data['name'];

        /// 拼接好图片地址
        task.imageUrl = '${result.data['url']}${task.key}';
        String uploadHost = (result.data['host'] ?? apiQiniuUpload).toString();
        if (!uploadHost.startsWith('http')) {
          uploadHost = '${Api.shareInstance().host}$uploadHost';
        }

        task.uploadRecords.add('开始上传 附件上传服务器地址：$uploadHost');
        task.uploadRecords.add('上传开始时间：${DateTime.now().toString()}');
        var response = await _dio.post(uploadHost,
            data: FormData.fromMap({
              'token': result.data['token'],
              'key': task.key,
              'file': task.multipartFile
            }), onSendProgress: (sent, total) {
          if (task._onUploadChanged != null) {
            ///800毫秒的间隔通知
            if (DateTime.now().millisecondsSinceEpoch -
                        refreshTime.millisecondsSinceEpoch >=
                    800 ||
                sent == total) {
              task.progress = (sent / total * 100).toInt();
              task.uploadRecords.add('上传中：task.progress：${task.progress}');
              task._onUploadChanged!(task);
              refreshTime = DateTime.now();
            }
          }
        }, cancelToken: task._cancelToken).catchError((err) {
          //错误处理
          if (err is DioError) {
            task.uploadRecords.add('上传报错  DioError：${err.toString()}');
            if (err.type == DioErrorType.cancel) {
              task.status = FileUploaderStatus.canceled;
            } else {
              task.status = FileUploaderStatus.failed;
              task.errMessage = err.message;
            }
          } else {
            task.status = FileUploaderStatus.failed;
            task.errMessage = err.toString();
            task.uploadRecords.add('上传报错：${err.toString()}');
          }
          return Future.value(Response(
              requestOptions: RequestOptions(path: apiQiniuUpload),
              statusCode: 500));
        });

        if (response.statusCode == 200) {
          //上传成功
          _finishedTasks.add(task);
          task.status = FileUploaderStatus.success;
        } else {
          //上传失败
          if (task.status == FileUploaderStatus.uploading) {
            task.status = FileUploaderStatus.failed;
            task.errMessage = response.data?.toString();
          }
        }
        task.uploadRecords.add(
            '上传结束：response.statusCode：${response.statusCode}  response.data：${response.data}');
        task.uploadRecords.add('上传结束时间：${DateTime.now().toString()}');

        //状态变化通知
        if (task._onUploadChanged != null) {
          task._onUploadChanged!(task);
        }
      } else {
        task.status = FileUploaderStatus.failed;
        task.errMessage = result.message;
        if (task._onUploadChanged != null) {
          task._onUploadChanged!(task);
        }
        task.uploadRecords.add('接口/api/image 返回状态 不是200');
        task.uploadRecords.add('任务结束时间：${DateTime.now().toString()}');
      }
    }
    _isRunning = false;

    return Future.value();
  }
}
